package com.hdax.dm.controller;

import cn.hutool.crypto.SecureUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hdax.dm.common.constant.ConstantData;
import com.hdax.dm.common.exception.DmException;
import com.hdax.dm.common.exception.DmUserLoginException;
import com.hdax.dm.dto.CommonResponse;
import com.hdax.dm.dto.DtoUtil;
import com.hdax.dm.dto.user.TokenDto;
import com.hdax.dm.entity.user.DmUser;
import com.hdax.dm.feign.user.DmUserFeign;
import com.hdax.dm.service.DmUserLoginService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping(path = "/user")
@CrossOrigin
public class DmUserLoginController {

    @Autowired
    private DmUserLoginService dmUserLoginService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private DmUserFeign userFeign;

    //局部异常处理
    @ExceptionHandler(value = {RuntimeException.class})
    public CommonResponse<Map<String,String>> exceptionHandler(DmException exception){
        return DtoUtil.returnFail(exception.getErrorCode(), exception.getErrorMsg());
    }


    //发送短信（用于手机号登录/注册:sms_number）
    @PostMapping(path = "/msg")
    public CommonResponse<String> msg(@RequestBody Map<String,String> params){
        String phoneNumber = params.get("phone");

        //手机号非空和格式判断
        if(phoneNumber == null || phoneNumber.trim().equals("")){
            throw new DmUserLoginException(ConstantData.ErrCode.NULL_PHONE_CODE,ConstantData.ErrMsg.NULL_PHONE_MSG);
        }

        //是否已发送验证码，存在则提示
        String code = redisTemplate.opsForValue().get("sms_"+phoneNumber);
        if(code != null){
            throw new DmUserLoginException("10008","请勿频繁获取验证码，60s有效");
        }

        //验证码
        int minValue = 100000;
        int maxValue = 999999;
        Random random = new Random();
        int rand = random.nextInt(maxValue);
        while (rand<minValue){
            rand = random.nextInt(maxValue);
        }

        //将验证码存储到redis
        redisTemplate.opsForValue().set("sms_".concat(phoneNumber),rand+"",60, TimeUnit.SECONDS);

        //异步消息发送,将手机号和验证码放进map集合传递给rabbitmq
        Map<String,String> p = new HashMap<>();
        p.put("phoneNumber",phoneNumber);
        p.put("vcode",rand+"");
        rabbitTemplate.convertAndSend("dmsms",p);

        return DtoUtil.returnSuccess("短信验证码发送成功");
    }

    //短信验证登录
    @PostMapping(path = "/msg/login")
    public CommonResponse<TokenDto> msglogin(@RequestBody Map<String,String> params,
                                             HttpServletRequest request)throws Exception{
        String phoneNumber = params.get("phone");
        String vcode = params.get("vcode");

        //验证码非空判断
        if(vcode == null || vcode.trim().equals("")){
            throw new DmUserLoginException("10003","请输入验证码");
        }
        //数据库验证码非空判断
        String code = redisTemplate.opsForValue().get("sms_"+phoneNumber);
        if(code == null){
            throw new DmUserLoginException("10004","请获取验证码，60s有效");
        }
        //验证码是否匹配
        if(!code.equals(vcode)){
            throw new DmUserLoginException("10005","请输入正确的验证码");
        }

        //获取用户信息
        DmUser dmUser = dmUserLoginService.msglogin(phoneNumber);

        //  判断手机号是否已存在，不存在即为注册
        if (dmUser==null){
            dmUser = new DmUser();
            dmUser.setPhone(params.get("phone"));
            dmUser.setPassword(SecureUtil.md5(params.get("password")));
            dmUser.setNickName("用户");
            dmUser.setSex("0");
            userFeign.addUserInfo(dmUser);
        }

        return DtoUtil.returnSuccess(generateToken(request,dmUser));
    }
    //密码验证登录
    @PostMapping(path = "/login")
    public CommonResponse<TokenDto> login(@RequestBody Map<String,String> params,
                                             HttpServletRequest request)throws Exception{
        String phoneNumber = params.get("phone");
        String password = params.get("password");

        DmUser dmUser = dmUserLoginService.login(phoneNumber,SecureUtil.md5(password));

        return DtoUtil.returnSuccess(generateToken(request,dmUser));
    }


    //发送短信（用于手机号密码注册:sms_zhuce_number）
    @PostMapping(path = "/code")
    public CommonResponse<String> code(@RequestBody Map<String,String> params){
        String phoneNumber = params.get("phone");
        if (userFeign.findByPhone(phoneNumber)!=null) {
            throw new DmException("0001","手机号已被注册");
        }
        //是否已发送验证码，存在则提示
        String code = redisTemplate.opsForValue().get("sms_zhuce_"+phoneNumber);
        if(code != null){
            throw new DmUserLoginException("10008","请勿频繁获取验证码，60s有效");
        }
        //验证码
        int minValue = 100000;
        int maxValue = 999999;
        Random random = new Random();
        int rand = random.nextInt(maxValue);
        while (rand<minValue){
            rand = random.nextInt(maxValue);
        }
        //将验证码存储到redis
        redisTemplate.opsForValue().set("sms_zhuce_".concat(phoneNumber)
                ,rand+"",60, TimeUnit.SECONDS);
        //异步消息发送,将手机号和验证码放进map集合传递给rabbitmq
        Map<String,String> p = new HashMap<>();
        p.put("phoneNumber",phoneNumber);
        p.put("vcode",rand+"");
        rabbitTemplate.convertAndSend("dmsms",p);
        return DtoUtil.returnSuccess("短信验证码发送成功");
    }

    //账号密码注册
    @RequestMapping(path = "/register")
    public CommonResponse<String> register(@RequestBody Map<String,String> params){
        //获取redis存储的验证码
        String code = redisTemplate.opsForValue().get("sms_zhuce_"+params.get("phone"));
        if (!code.equals(params.get("vcode"))){
            throw new DmException("0001","验证码不正确");
        }
        DmUser dmUser = new DmUser();
        dmUser.setPhone(params.get("phone"));
        dmUser.setPassword(SecureUtil.md5(params.get("password")));
        dmUser.setNickName("用户");
        userFeign.addUserInfo(dmUser);
        return DtoUtil.returnSuccess("注册成功");
    }


    //退出登录
    @PostMapping(path = "/logout")
    public void logout(@RequestBody Map<String,String> params){
        String tokenKey = params.get("info");
        redisTemplate.delete(tokenKey);
        System.out.println("请求退出！");
    }

    //生成令牌
    public TokenDto generateToken(HttpServletRequest request,
                                  DmUser dmUser)throws Exception{
        TokenDto tokenDto = new TokenDto();
        BeanUtils.copyProperties(dmUser,tokenDto);

        //创建token   token:PC-UserId-phoneNumber-yyyyMMddHHmmss-MD5(user-agent)
        //开始
        String userAgent = request.getHeader("User-Agent");
        StringBuffer buffer = new StringBuffer("token:PC-");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        Date date = new Date();
        buffer.append(tokenDto.getUserId());
        buffer.append("-").append(tokenDto.getPhone()).
                append("-").append(dateFormat.format(date))
                .append("-").append(SecureUtil.md5(userAgent).substring(12));
        ObjectMapper objectMapper = new ObjectMapper();
        redisTemplate.opsForValue().set(buffer.toString(),
                objectMapper.writeValueAsString(dmUser),2L,TimeUnit.HOURS);
        //结束

        //返回用户信息
        tokenDto.setToken(buffer.toString());
        tokenDto.setGenTime(date.getTime());
        tokenDto.setExtTime(date.getTime()+2L * 60 * 60 * 1000);
        return tokenDto;
    }
}
